using System;
using System.IO;
using System.Net.Sockets;
using OracleInternal.Common;

namespace OracleInternal.Network
{
	internal class DataPacket : Packet
	{
		internal static readonly int NSPDAFZER = 0;

		internal static readonly int NSPDAFMOR = 32;

		internal static readonly int NSPDAFEOF = 64;

		internal static readonly int NSPDAFRTN = 32768;

		internal int m_packetOffset;

		internal int m_dataFlags;

		internal int m_availableBytesToSend;

		internal int m_availableBytesToRead;

		internal bool m_isBufferFull;

		internal bool m_isBufferEmpty;

		internal DataPacket(SessionContext sessCtx, int pktLength)
			: base(sessCtx, pktLength, 6, 0)
		{
			Initialize(pktLength);
		}

		internal DataPacket(SessionContext sessCtx)
			: base(sessCtx, sessCtx.m_sessionDataUnit, 6, 0)
		{
			Initialize(sessCtx.m_sessionDataUnit);
		}

		internal static void setLength(byte[] hdr, int length, SessionContext SCtx)
		{
			if (!SCtx.m_NSHandshakeComplete || SCtx.m_myversion < SessionContext.NSVSNLSD)
			{
				hdr[TNSPacketOffsets.NSPHDLEN] = (byte)(length / 256);
				hdr[TNSPacketOffsets.NSPHDLEN + 1] = (byte)(length % 256);
				return;
			}
			hdr[TNSPacketOffsets.NSPHDLEN + 3] = (byte)((uint)length & 0xFFu);
			hdr[TNSPacketOffsets.NSPHDLEN + 2] = (byte)((uint)HelperClass.URShift(length, 8) & 0xFFu);
			hdr[TNSPacketOffsets.NSPHDLEN + 1] = (byte)((uint)HelperClass.URShift(length, 16) & 0xFFu);
			hdr[TNSPacketOffsets.NSPHDLEN] = (byte)((uint)HelperClass.URShift(length, 24) & 0xFFu);
		}

		internal static void InitForSend(byte[] hdr, int length, SessionContext SCtx)
		{
			setLength(hdr, length, SCtx);
			hdr[TNSPacketOffsets.NSPDAFLG] = (byte)(NSPDAFZER / 256);
			hdr[TNSPacketOffsets.NSPDAFLG + 1] = (byte)(NSPDAFZER % 256);
			hdr[TNSPacketOffsets.NSPHDTYP] = 6;
			hdr[TNSPacketOffsets.NSPHDFLGS] = 0;
			hdr[TNSPacketOffsets.NSPHDHSM] = 0;
			hdr[TNSPacketOffsets.NSPHDHSM + 1] = 0;
		}

		internal override void Receive()
		{
			base.Receive();
			if ((m_flags & Packet.NSPFSID) > 0)
			{
				m_length -= Packet.NSPSID_SZ;
			}
			m_dataOffset = (m_packetOffset = TNSPacketOffsets.NSPDADAT);
			m_dataLength = m_length - m_dataOffset;
			m_dataFlags = m_dataBuffer[TNSPacketOffsets.NSPDAFLG] & 0xFF;
			m_dataFlags <<= 8;
			m_dataFlags |= m_dataBuffer[TNSPacketOffsets.NSPDAFLG + 1] & 0xFF;
			if (m_type == TNSPacketType.DATA && m_dataLength == 0)
			{
				m_type = TNSPacketType.NULL;
			}
		}

		internal override void Send()
		{
			Send(NSPDAFZER);
		}

		internal void Send(int dataFlags)
		{
			m_dataBuffer[TNSPacketOffsets.NSPDAFLG] = (byte)(m_dataFlags / 256);
			m_dataBuffer[TNSPacketOffsets.NSPDAFLG + 1] = (byte)(m_dataFlags % 256);
			if (m_sessionCtx.m_SID != null)
			{
				Buffer.BlockCopy(m_sessionCtx.m_SID, 0, m_dataBuffer, m_packetOffset, Packet.NSPSID_SZ);
				m_packetOffset += Packet.NSPSID_SZ;
			}
			SetBufferLength(m_packetOffset);
			try
			{
				m_sessionCtx.m_socketStream.Write(m_dataBuffer, 0, m_packetOffset);
				if (ProviderConfig.m_bTraceLevelNetwork)
				{
					Trace.Write(OracleTraceLevel.Network, OracleTraceTag.BulkCopy, m_dataBuffer, 0, m_packetOffset);
				}
			}
			catch (IOException ex)
			{
				if (m_sessionCtx.m_SID == null)
				{
					throw ex;
				}
				Exception innerException = ex.InnerException;
				while (innerException != null && !(innerException is SocketException))
				{
					innerException = innerException.InnerException;
				}
				if (innerException == null || ((SocketException)innerException).ErrorCode != 10054)
				{
					throw ex;
				}
				ConnectionOption connectionOption = new AddressResolution(m_sessionCtx.m_reconAddr, m_sessionCtx.m_conops.SNOConfig).ResolveConnectionString();
				if (connectionOption == null)
				{
					throw ex;
				}
				m_sessionCtx.m_transportAdapter.Connect(connectionOption);
				m_sessionCtx.m_socketStream = m_sessionCtx.m_transportAdapter.GetStream();
				m_sessionCtx.m_socketStream.Write(m_dataBuffer, 0, m_packetOffset);
				if (ProviderConfig.m_bTraceLevelNetwork)
				{
					Trace.Write(OracleTraceLevel.Network, OracleTraceTag.BulkCopy, m_dataBuffer, 0, m_packetOffset);
				}
			}
			m_packetOffset = TNSPacketOffsets.NSPDADAT;
			m_availableBytesToSend = 0;
			m_isBufferFull = false;
		}

		internal void Initialize(int length)
		{
			m_dataOffset = (m_packetOffset = TNSPacketOffsets.NSPDADAT);
			m_dataLength = length - m_dataOffset;
			m_dataFlags = NSPDAFZER;
		}

		internal void Initialize()
		{
			Initialize(m_totalLength);
		}

		internal void SetBufferLength(int length)
		{
			setLength(m_dataBuffer, length, m_sessionCtx);
		}

		internal int PutDataInBuffer(byte[] userBuffer, int offset, int length)
		{
			int num = 0;
			num = ((m_totalLength - m_packetOffset > length) ? length : (m_totalLength - m_packetOffset));
			if (num > 0)
			{
				Buffer.BlockCopy(userBuffer, offset, m_dataBuffer, m_packetOffset, num);
				m_packetOffset += num;
				m_isBufferFull = ((m_packetOffset == m_totalLength) ? true : false);
				m_availableBytesToSend = ((m_dataOffset < m_packetOffset) ? (m_packetOffset - m_dataOffset) : 0);
			}
			return num;
		}

		internal int getDataFromBuffer(byte[] userBuffer, int offset, int length)
		{
			int num = 0;
			num = ((m_length - m_packetOffset > length) ? length : (m_length - m_packetOffset));
			if (num > 0)
			{
				Buffer.BlockCopy(m_dataBuffer, m_packetOffset, userBuffer, offset, num);
				m_packetOffset += num;
				m_isBufferEmpty = ((m_packetOffset == m_length) ? true : false);
				m_availableBytesToRead = m_dataOffset + m_dataLength - m_packetOffset;
			}
			return num;
		}
	}
}
